package cn.sunxiansheng.redis.utils;

import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

/**
 * Description: Redis的String类型操作
 *
 * @Author sun
 * @Create 2024/11/14 14:50
 * @Version 1.1
 */
public class RString extends RBase {

    /**
     * 构造器给父类注入RedisTemplate
     *
     * @param redisTemplate RedisTemplate实例
     */
    public RString(RedisTemplate<String, Object> redisTemplate) {
        super(redisTemplate);
    }

    /**
     * 设置缓存值
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value) {
        validateKeyAndValue(key, value);
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 设置缓存值并设置过期时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     * @param unit    时间单位
     */
    public void setWithExpire(String key, Object value, final long timeout, final TimeUnit unit) {
        validateKeyAndValue(key, value);
        validateTimeoutAndUnit(timeout, unit);
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 设置缓存值并设置过期时间（单位：秒）
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     */
    public void setWithExpire(String key, Object value, final long timeout) {
        setWithExpire(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置缓存值，如果key不存在，则设置成功，并指定过期时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     * @param unit    时间单位
     * @return 是否设置成功
     */
    public Boolean setIfAbsent(String key, Object value, long timeout, TimeUnit unit) {
        validateKeyAndValue(key, value);
        validateTimeoutAndUnit(timeout, unit);
        return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
    }

    /**
     * 设置缓存值，如果key不存在，则设置成功，并指定过期时间（单位：秒）
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     * @return 是否设置成功
     */
    public Boolean setIfAbsent(String key, Object value, long timeout) {
        return setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 获取缓存值并进行类型转换
     *
     * @param key  键
     * @param type 返回值的类型
     * @return 转换后的对象，若类型不匹配则抛出异常
     */
    public <T> T get(String key, Class<T> type) {
        Object value = redisTemplate.opsForValue().get(key);
        return convertValue(value, type);
    }

    /**
     * 获取缓存值并设置新值
     *
     * @param key   键
     * @param value 新值
     * @param type  返回值的类型
     * @param <T>   返回值的类型
     * @return 旧值，类型为 T
     */
    public <T> T getAndSet(String key, T value, Class<T> type) {
        Object oldValue = redisTemplate.opsForValue().getAndSet(key, value);
        return convertValue(oldValue, type);
    }

    /**
     * 根据 delta 值调整缓存中的数值
     *
     * @param key   键
     * @param delta 调整步长，正数表示增加，负数表示减少
     * @return 调整后的值
     */
    public Long changeByDelta(String key, long delta) {
        if (key == null) {
            throw new IllegalArgumentException("Key 不能为空！");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 验证键和值的合法性
     */
    private void validateKeyAndValue(String key, Object value) {
        if (key == null || value == null) {
            throw new IllegalArgumentException("Key 和 Value 不能为空！");
        }
    }

    /**
     * 验证超时时间和单位的合法性
     */
    private void validateTimeoutAndUnit(long timeout, TimeUnit unit) {
        if (timeout <= 0 || unit == null) {
            throw new IllegalArgumentException("超时时间必须大于 0，时间单位不能为空！");
        }
    }
}